package io.xxx.cyb.sync.impl

import com.alibaba.fastjson.JSONObject
import io.xxx.cyb.model.Document
import io.xxx.cyb.model.Store
import io.xxx.cyb.sync.Porter
import io.xxx.cyb.util.dateTimeFormatter
import io.xxx.cyb.util.toLocalDateTime
import org.springframework.http.HttpMethod
import org.springframework.http.RequestEntity
import org.springframework.web.util.UriComponentsBuilder
import java.time.Duration
import java.time.LocalDateTime

/**
 * 京东
 */
abstract class JdPorter(sid: String) : Porter(sid) {

    protected val httpUrl = "http://114.67.201.245/api"

    protected inline fun <reified T> getResponse(entity: RequestEntity<T>): T {
        return restTemplate.exchange(entity, T::class.java).body!!
    }

    protected open fun getResponse(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long = 0
    ): JSONObject {
        return JSONObject()
    }

    protected abstract fun buildRequest(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long = 0,
    ): Map<String, Any>
}

abstract class JdProxyPorter(sid: String) : JdPorter(sid) {

    override val duration: Duration = Duration.ofDays(1)

    protected abstract val requestClass: String

    override fun getResponse(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long
    ): JSONObject {
        val request = buildRequest(store, startTime, endTime, pageNo)
        val url = UriComponentsBuilder
            .fromHttpUrl(httpUrl)
            .path("/execute")
            .queryParam("requestClass", requestClass)
            .toUriString()
        val response = restTemplate.postForEntity(url, request, JSONObject::class.java).body!!
        if (response.getString("code") != "0") {
            throwException(
                javaClass.simpleName,
                requestClass,
                response.getString("code"),
                response.getString("msg")
            )
        }
        return response
    }
}

// 订单
@Suppress("unused")
class JdTradePorter(sid: String) : JdPorter(sid) {

    override fun getCount(store: Store, startTime: LocalDateTime, endTime: LocalDateTime, parameter: Any?): Long {
        val urlBuilder = UriComponentsBuilder
            .fromHttpUrl(httpUrl)
            .path("/trades/count")
        val request = buildRequest(store, startTime, endTime)
        request.entries.forEach { urlBuilder.queryParam(it.key, it.value) }
        val entity = RequestEntity<Long>(null, HttpMethod.GET, urlBuilder.build().toUri())
        return getResponse(entity)
    }

    override fun getData(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Long
    ): List<Document> {
        val urlBuilder = UriComponentsBuilder
            .fromHttpUrl(httpUrl)
            .path("/trades/data")
        val request = buildRequest(store, startTime, endTime, pageNo)
        request.entries.forEach { urlBuilder.queryParam(it.key, it.value) }
        val entity = RequestEntity<List<Map<String, *>>>(null, HttpMethod.GET, urlBuilder.build().toUri())
        val response = getResponse(entity)
        return response.map {
            val value = JSONObject(it)
            Document(value.getString("orderId"), value, value.getString("pushModified").toLocalDateTime())
        }
    }

    override fun buildRequest(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long
    ): Map<String, Any> {
        return mapOf(
            "venderId" to store.oid!!,
            "startTime" to startTime.format(dateTimeFormatter),
            "endTime" to endTime.format(dateTimeFormatter),
            "pageNo" to pageNo,
        )
    }
}

// 退单
@Suppress("unused")
class JdRefundPorter(sid: String) : JdProxyPorter(sid) {

    override val pageSize = 50

    override val requestClass = "com.jd.open.api.sdk.request.refundapply.PopAfsSoaRefundapplyQueryPageListRequest"

    override fun getCount(store: Store, startTime: LocalDateTime, endTime: LocalDateTime, parameter: Any?): Long {
        return getResponse(store, startTime, endTime)
            .getJSONObject("queryResult")
            .getLong("totalCount")
    }

    override fun getData(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Long
    ): List<Document> {
        val response = getResponse(store, startTime, endTime)
            .getJSONObject("queryResult")
            .getJSONArray("result")
        return response.map {
            @Suppress("unchecked_cast")
            val value = JSONObject(it as Map<String, Any>)
            Document(
                value.getString("id"),
                value.getString("orderId"),
                value,
                value.getString("checkTime").toLocalDateTime()
            )
        }
    }

    override fun buildRequest(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long
    ): Map<String, Any> {
        return mapOf(
            "applyTimeStart" to startTime.format(dateTimeFormatter),
            "applyTimeEnd" to endTime.format(dateTimeFormatter),
            "pageIndex" to pageNo,
            "pageSize" to pageSize,
        )
    }
}

// 自营订单
@Suppress("unused")
class JdZyTradePorter(sid: String) : JdProxyPorter(sid) {

    override val pageSize = 50

    override val requestClass = "com.jd.open.api.sdk.request.supplier.DropshipDpsSearchRequest"

    override fun getCount(store: Store, startTime: LocalDateTime, endTime: LocalDateTime, parameter: Any?): Long {
        return getResponse(store, startTime, endTime)
            .getJSONObject("searchResult")
            .getLong("recordCount")
    }

    override fun getData(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Long
    ): List<Document> {
        val response = getResponse(store, startTime, endTime)
            .getJSONObject("searchResult")
            .getJSONArray("resultDtoList")
        return response.map {
            @Suppress("unchecked_cast")
            val value = JSONObject(it as Map<String, Any>)
            Document(
                value.getString("customOrderId"),
                value,
                value.getString("orderTime").toLocalDateTime()
            )
        }
    }

    override fun buildRequest(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long
    ): Map<String, Any> {
        return mapOf(
            "beginDate" to startTime.format(dateTimeFormatter),
            "endDate" to endTime.format(dateTimeFormatter),
            "page" to pageNo,
            "pageSize" to pageSize
        )
    }
}

// 自营退单
@Suppress("unused")
class JdZyRefundPorter(sid: String) : JdProxyPorter(sid) {

    override val pageSize = 50

    override val requestClass = "com.jd.open.api.sdk.request.supplier.DropshipDpsSearchpreRequest"

    override fun getCount(store: Store, startTime: LocalDateTime, endTime: LocalDateTime, parameter: Any?): Long {
        return getResponse(store, startTime, endTime)
            .getJSONObject("searchPreResult")
            .getLong("recordCount")
    }

    override fun getData(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        parameter: Any?,
        pageNo: Long
    ): List<Document> {
        val response = getResponse(store, startTime, endTime)
            .getJSONObject("searchPreResult")
            .getJSONArray("resultDtoList")
        return response.map {
            @Suppress("unchecked_cast")
            val value = JSONObject(it as Map<String, Any>)
            Document(
                value.getString("id"),
                value.getString("customOrderId"),
                value,
                value.getString("orderTime").toLocalDateTime()
            )
        }
    }

    override fun buildRequest(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Long
    ): Map<String, Any> {
        return mapOf(
            "beginDate" to startTime.format(dateTimeFormatter),
            "endDate" to endTime.format(dateTimeFormatter),
            "page" to pageNo,
            "pageSize" to pageSize
        )
    }
}